
trait Printable {
    fn stringify(&self) -> String;
}

impl Printable for i32 {
    fn stringify(&self) -> String {
        self.to_string()
    }
}

impl Printable for i64 {
    fn stringify(&self) -> String {
        self.to_string()
    }
}


//impl for all trait_object 
//NOTE: impl Trait1 for dyn Trait ; [1]
//NOTE: impl<'a> Trait1 for dyn Trait + 'a ; [2]


#[cfg(test)]
mod test{
    use super::*;
    #[test]
    fn trait_object_declare_call(){
        assert_eq!("10", 10_i32.stringify());

        fn print(a: Box<dyn Printable>){ //NOTE: dyn Printable declare
            println!("{}", a.stringify());
        }
        print(Box::<i32>::new(10000));  //NOTE: call dyn Printable

    }

    #[test]
    fn impl_for_all_trait_object(){
        //NOTE: [1] impl functions for all trait-object
        impl dyn Printable {        
            pub fn hello(&self){
                println!("{}, hello impl dyn Printable", self.stringify());
            }
        }

        let trait_obj_i32 = Box::<i32>::new(20) as Box<dyn Printable>;
        trait_obj_i32.hello();

        let trait_obj_i64 = Box::<i64>::new(40) as Box<dyn Printable>;
        trait_obj_i64.hello();

    }

    #[test]
    fn impl_trait_and_lifetime(){
        use std::fmt;

        //NOTE: ...... for dyn Printable + 'a   [2]
        impl<'a> fmt::Display for dyn Printable + 'a { 
            fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                write!(formatter, "Display: {}", self.stringify())
            }
        }

        let trait_obj_i32 = Box::<i32>::new(23) as Box<dyn Printable>;
        println!("{}", trait_obj_i32);
    }
}
